﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
using System.Windows.Forms;

using GMap.NET;

using FLEN_Sim.config;

namespace FLEN_Sim.funct
{
    /// <summary>
    /// Stellt Methoden zur Umwandlung von Adresse in Lat/Lon und andersrum zur Verfügung.
    /// </summary>
    public class GeoCoder
    {
        public static PointLatLng getLocationNominatim(string address, int City)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://nominatim.openstreetmap.org/search/?q="+address+"&format=xml&polygon=0&addressdetails=0");
            request.UserAgent = Config.USERAGENT;
            request.Headers.Add(HttpRequestHeader.From, Config.EMAIL);
            request.Headers.Add("X-Client", "FLEN-Sim; http://code.google.com/p/flen-sim/; s.markert87@googlemail.com");
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            XmlReaderSettings settings = new XmlReaderSettings();
            settings.DtdProcessing = DtdProcessing.Parse;
            XmlTextReader reader = new XmlTextReader(response.GetResponseStream());

            bool carryOn = true;
            
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element && reader.Name.Equals("place"))
                {
                    reader.MoveToAttribute("lat");
                    double lat = Double.Parse(reader.Value.Replace(".",","));

                    reader.MoveToAttribute("lon");
                    double lon = Double.Parse(reader.Value.Replace(".", ","));

                    reader.MoveToAttribute("display_name");
                    string display_name = reader.Value;

                    if (display_name.Contains(CityNumbers.getCityByNumber(City)))
                    {
                        carryOn = false;
                    }


                    if (!carryOn)
                    {
                        response.Close();
                        return new PointLatLng(lat, lon);
                    }
                }
            }

            reader.Close();
            response.Close();


            return new PointLatLng();
        }

        public static string getReverseLocationNominatim(PointLatLng point, ushort cityNumber)
        {
            return GeoCoder.getReverseLocationNominatim(cityNumber);
        }

        public static string getReverseLocationNominatim(ushort cityNumber)
        {
            string city = "", road = "";
            int housenumber = 0, plz = 0;

            do
            {

                Random rnd = new Random();
                double max = Config.EN_BOUNDARY_N - 51.0;
                double min = Config.EN_BOUNDARY_S - 51.0;

                double lat = NextDouble(rnd, min, max) + 51.0;

                max = Config.EN_BOUNDARY_E - 7.0;
                min = Config.EN_BOUNDARY_W - 7.0;

                double lon = NextDouble(rnd, min, max) + 7.0;

            
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://nominatim.openstreetmap.org/reverse?format=xml&lat=" + lat.ToString().Replace(",", ".") + "&lon=" + lon.ToString().Replace(",", ".") + "&zoom=18&addressdetails=1");
                request.UserAgent = Config.USERAGENT;
                request.Headers.Add(HttpRequestHeader.From, Config.EMAIL);
                request.Headers.Add("X-Client", "FLEN-Sim; http://code.google.com/p/flen-sim/; s.markert87@googlemail.com");
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                XmlReaderSettings settings = new XmlReaderSettings();
                settings.DtdProcessing = DtdProcessing.Parse;
                XmlTextReader reader = new XmlTextReader(response.GetResponseStream());

                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        switch (reader.Name)
                        {
                            case "road":
                                reader.Read();
                                road = reader.Value;
                                break;
                            case "city":
                                reader.Read();
                                city = reader.Value;
                                break;
                            case "postcode":
                                reader.Read();
                                plz = Int32.Parse(reader.Value);
                                break;
                            case "boundary":
                                reader.Read();
                                plz = Int32.Parse(reader.Value);
                                break;
                            case "house_number":
                                reader.Read();
                                housenumber = Int32.Parse(reader.Value);
                                break;
                            default:
                                break;
                        }
                    }
                }

                reader.Close();
                response.Close();
            }
            while (!city.Equals(CityNumbers.getCityByNumber(cityNumber)));

            if (road == "" || city == "")
                return null;
            else
            {
                if (housenumber == 0)
                {
                    return String.Format("{0} {1:D}, {2:D} {3}, Germany", road, housenumber, plz, city);
                }
                else
                {
                    return String.Format("{0}, {1:D} {2}, Germany", road, plz, city);
                }
            }
        }

        private static double NextDouble(Random rng, double min, double max)
        {
            return min + (rng.NextDouble() * (max - min));
        }

        public static string getRandomAdress(ushort cityNumber)
        {
            switch (cityNumber)
            {
                case 1:
                    {
                        Stream stream = File.OpenRead("data\\StreetsWitten.csv");
                        {
                            StreamReader sr = new StreamReader(stream, Encoding.UTF8);

                            Random rnd = new Random();
                            List<string> streets = new List<string>();

                            string[] tiles = null;

                            do
                            {
                                if (sr.EndOfStream)
                                {
                                    sr.Close();
                                    stream = File.OpenRead("data\\StreetsWitten.csv");
                                }

                                int rnd_letter = rnd.Next(1, 26);
                                char street_begin = Config.ALPHABET[rnd_letter];

                                if (street_begin.Equals('X') || street_begin.Equals('Y'))
                                    street_begin = Config.ALPHABET[rnd_letter - (rnd.Next(1, 15))];
                                
                                string temp = "";                                

                            
                                while ((temp = sr.ReadLine()) != "" && temp != null)
                                {
                                    if (temp != null && temp.Equals(street_begin.ToString()))
                                    {
                                        while ((temp = sr.ReadLine()).Length != 1)
                                        {
                                            tiles = temp.Split(',');
                                            streets.Add(tiles[0]);
                                        }

                                        break;
                                    }
                                }
                            }
                            while (streets.Count == 0);

                            int rnd_streetNumb = rnd.Next(0, streets.Count - 1);
                            string rnd_street = streets[rnd_streetNumb];

                            int rnd_houseNumb = -1;

                            if (tiles != null && tiles.Length > 1 && !tiles[1].Equals(""))
                            {
                                string[] tilesNumb = tiles[1].Split('-');
                                rnd_houseNumb = rnd.Next(Int32.Parse(tilesNumb[0]), Int32.Parse(tilesNumb[1]));
                            }
                            else
                            {
                                rnd_houseNumb = rnd.Next(1, 70);
                            }

                            string adress = rnd_street.ToString() + " " + rnd_houseNumb + ", Witten, Germany";

                            stream.Close();

                            return adress;
                        }
                        
                    }
                default:
                    break;
            }

            return null;
        }
    }
}
